/* ***** BEGIN LICENSE BLOCK *****
 *   Version: MPL 1.1/GPL 2.0/LGPL 2.1
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 * 
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is Seoprofesional
 *
 * The Initial Developer of the Original Code is
 * Petr Blahoš.
 * Portions created by the Initial Developer are Copyright (C) 2009
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s):
 *
 * Alternatively, the contents of this file may be used under the terms of
 * either the GNU General Public License Version 2 or later (the "GPL"), or
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 * in which case the provisions of the GPL or the LGPL are applicable instead
 * of those above. If you wish to allow use of your version of this file only
 * under the terms of either the GPL or the LGPL, and not to allow others to
 * use your version of this file under the terms of the MPL, indicate your
 * decision by deleting the provisions above and replace them with the notice
 * and other provisions required by the GPL or the LGPL. If you do not delete
 * the provisions above, a recipient may use your version of this file under
 * the terms of any one of the MPL, the GPL or the LGPL.
 * 
 * ***** END LICENSE BLOCK ***** */

var SeoprofesionalController = {
// flags
FETCHER_NOBARS: 1,
// end of flags

SEOP_BAR_SIZE: 50,
srank_fetcher: {
	enabled: 1,
	flags: 0,
	name: "srank",		// the rank's name
	shortname: "S", 
	id: 2,			// the rank's ID
	refresh: 0,
	coherent: 0,		// if 0, the lines in the chart are always horizontal and non-continuos.
				// if 1, the lines are continuous
	color: "#F00",
	get_max: function(vals) { return 100; },
	fetch: function(tab, uri) {
		var req = new XMLHttpRequest();
		req.onreadystatechange = function(evt) {
			SeoprofesionalController.srank_fetcher.onreadystatechange(req, evt, tab, uri);
		};
		var body = '<?xml version="1.0" encoding="UTF-8"?>' +
		    '<methodCall>' +
			'<methodName>getRank</methodName>' +
			'<params>' +
			    '<param>' +
				'<value>' +
				    '<string>0</string>' +
				'</value>' +
			    '</param>' +
			    '<param>' +
				'<value>' +
				    '<string>' + uri + '</string>' +
				'</value>' +
			    '</param>' +
			    '<param>' +
				'<value>' +
				    '<i4>0</i4>' +
				'</value>' +
			    '</param>' +
			'</params>' +
		    '</methodCall>';	
		req.open("POST", "http://srank.seznam.cz/RPC2");
		req.setRequestHeader("Content-Type", "text/xml");
		req.setRequestHeader("Host", "srank.seznam.cz");
		req.setRequestHeader("Connection", "Close");
		//req.setRequestHeader("", "");
		req.send(body);
		
	},
	onreadystatechange: function(req, evt, tab, uri) {
		if (""+tab.contentDocument.location!=uri) {
			SeoprofesionalTools.LOG("The tab content has changed. Aborting the request.");
			req.abort();
			return ;
		}
		if (4==req.readyState) {  
			if(200==req.status) {
				var rank = null;
				var r = /<name>rank<\/name>\s*<value><i[a-z0-9]*>([^<]*)<\/i/gi;
				var m = r.exec(req.responseText);
				if (null!=m) {
				    rank = Math.floor(100*m[1]/255);
				    m = r.exec();
				    while (null!=m) {
					m = r.exec();
				    }
				}
				if (null==rank) {
					tab.setAttribute("x-seop-value-" + this.name, 0);
					SeoprofesionalTools.LOG("error fetching S-RANK for " + uri + "\n|" + req.responseText + "|");
				} else {
					tab.setAttribute("x-seop-value-" + this.name, rank);
					SeoprofesionalController.seopdb.add_rank(uri, this.id, rank);
				}
			}
			tab.setAttribute("x-seop-status-" + this.name, req.status);
			SeoprofesionalTools.LOG("setting status: " + this.name + "-status --> " + req.status);
			if (gBrowser.selectedBrowser==tab) {
				SeoprofesionalController.tabSelected(null);
			}
		}
	},
	is_my_id: function(id) {
		var prefix = "seop-"+this.name;
		return prefix==id.substring(0, prefix.length);
	},
	_x_sentinel_: 0
},
pagerank_fetcher: {
	enabled: 1,
	flags: 0,
	name: "pagerank",		// the rank's name
	shortname: "G",
	id: 3,			// the rank's ID
	refresh: 0,
	coherent: 0,		// if 0, the lines in the chart are always horizontal and non-continuos.
				// if 1, the lines are continuous
	color: "#00F",
	get_max: function(vals) { return 10; },
	get_pr_url: function(url_in) {
		//from: http://www.7is7.com/software/bookmarklets/googlepagerank.html
		var zF = function(a,b) {
			var z=parseInt(80000000,16);
			if(z&a){ a=a>>1;a&=~z;a|=0x40000000;a=a>>(b-1);
			}else{ a=a>>b; }
			return(a);
		},
		mix=function(a,b,c){
			a-=b;a-=c;a^=(zF(c,13));b-=c;b-=a;b^=(a<<8);c-=a;c-=b;c^=(zF(b,13));
			a-=b;a-=c;a^=(zF(c,12));b-=c;b-=a;b^=(a<<16);c-=a;c-=b;c^=(zF(b,5));
			a-=b;a-=c;a^=(zF(c,3));b-=c;b-=a;b^=(a<<10);c-=a;c-=b;c^=(zF(b,15));
			return(new Array((a),(b),(c)));
		},
		GoogleCH=function(url,length){
			if(arguments.length==1)length=url.length;
			var a=0x9E3779B9,b=0x9E3779B9,c=0xE6359A60,k=0,len=length,mx=new Array();
			while(len>=12){
				a+=(url[k+0]+(url[k+1]<<8)+(url[k+2]<<16)+(url[k+3]<<24));
				b+=(url[k+4]+(url[k+5]<<8)+(url[k+6]<<16)+(url[k+7]<<24));
				c+=(url[k+8]+(url[k+9]<<8)+(url[k+10]<<16)+(url[k+11]<<24));
				mx=mix(a,b,c);a=mx[0];b=mx[1];c=mx[2];k+=12;len-=12;
			}
			c+=length;
			switch(len){
			case 11:c+=url[k+10]<<24;
			case 10:c+=url[k+9]<<16;
			case 9:c+=url[k+8]<<8;
			case 8:b+=(url[k+7]<<24);
			case 7:b+=(url[k+6]<<16);
			case 6:b+=(url[k+5]<<8);
			case 5:b+=(url[k+4]);
			case 4:a+=(url[k+3]<<24);
			case 3:a+=(url[k+2]<<16);
			case 2:a+=(url[k+1]<<8);
			case 1:a+=(url[k+0]);
			}
			mx=mix(a,b,c);
			if(mx[2]<0)return(0x100000000+mx[2]);
			else{ return(mx[2]); }
		},
		strord=function(string){
			var result=new Array();
			for(i=0;i<string.length;i++){
				result[i]=string[i].charCodeAt(0);
			}
			return(result);
		};
		return 'http://www.google.com/search?client=navclient-auto&ch=6'+GoogleCH(strord('info:'+url_in))+'&features=Rank&q=info:'+encodeURIComponent(url_in);
		//return '/search?client=navclient-auto&ch=6'+GoogleCH(strord('info:'+url_in))+'&features=Rank&q=info:'+encodeURIComponent(url_in);
	},
	fetch: function(tab, uri) {
		var req = new XMLHttpRequest();
		req.onreadystatechange = function(evt) {
			SeoprofesionalController.pagerank_fetcher.onreadystatechange(req, evt, tab, uri);
		};
		SeoprofesionalTools.LOG("pagerank request:" + SeoprofesionalController.pagerank_fetcher.get_pr_url(uri) + "<");
		req.open("GET", SeoprofesionalController.pagerank_fetcher.get_pr_url(uri));
		//req.setRequestHeader("Host", "www.google.com");
		req.setRequestHeader("Connection", "Close");
		req.setRequestHeader("User-Agent", "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.0.6) Gecko/20060728 Firefox/1.5");
		//req.setRequestHeader("", "");
		req.send(null);
		
	},
	onreadystatechange: function(req, evt, tab, uri) {
		if (""+tab.contentDocument.location!=uri) {
			SeoprofesionalTools.LOG("The tab content has changed. Aborting the request.");
			req.abort();
			return ;
		}
		if (4==req.readyState) {  
			if(200==req.status) {
				var rank = null;
				var t = req.responseText;
				if (t.lastIndexOf(':')!=-1) {
					rank = parseInt(t.substring(t.lastIndexOf(':')+1));
				}
				if (null==rank) {
					tab.setAttribute("x-seop-value-" + this.name, 0);
					SeoprofesionalTools.LOG("error fetching PAGE RANK for " + uri + "\n>" + req.responseText + "<");
				} else {
					tab.setAttribute("x-seop-value-" + this.name, rank);
					SeoprofesionalController.seopdb.add_rank(uri, this.id, rank);
				}
			}
			tab.setAttribute("x-seop-status-" + this.name, req.status);
			SeoprofesionalTools.LOG("setting status: " + this.name + "-status --> " + req.status);
			if (gBrowser.selectedBrowser==tab) {
				SeoprofesionalController.tabSelected(null);
			}
		}
	},
	is_my_id: function(id) {
		var prefix = "seop-"+this.name;
		return prefix==id.substring(0, prefix.length);
	},
	_x_sentinel_: 0
},
ylinks_fetcher: {
	enabled: 1,
	flags: 1, //FIXME: should be FETCHER_NOBARS,
	name: "ylinks",		// the rank's name
	shortname: "Y", 
	id: 4,			// the rank's ID
	refresh: 0,
	coherent: 1,		// if 0, the lines in the chart are always horizontal and non-continuos.
				// if 1, the lines are continuous
	color:	"#0524e1",
	appid:	"YahooDemo",
	get_max: function(vals) {
		if (null==vals) {
			return 100;
		}
		try {
			var m = 5;
			for (var i = 0;i<vals.length;i++) {
				if (vals[i][1]>m)
					m = vals[i][1];
			//2*vals[vals.length-1][1];
			}
			return m;
		} catch (e) {}
		return 100;
	},
	fetch: function(tab, uri) {
		var req = new XMLHttpRequest();
		req.onreadystatechange = function(evt) {
			SeoprofesionalController.ylinks_fetcher.onreadystatechange(req, evt, tab, uri);
		};
		req.open("GET", "http://search.yahooapis.com/SiteExplorerService/V1/inlinkData?appid="
			+ SeoprofesionalController.ylinks_fetcher.appid + "&query="+escape(uri)+"&results=0&output=json")
		req.setRequestHeader("Host", "search.yahooapis.com");
		req.setRequestHeader("Connection", "Close");
		req.send(null);
	},
	onreadystatechange: function(req, evt, tab, uri) {
		if (""+tab.contentDocument.location!=uri) {
			SeoprofesionalTools.LOG("The tab content has changed. Aborting the request.");
			req.abort();
			return ;
		}
		if (4==req.readyState) {  
			if(200==req.status) {
				var rank = null;
				SeoprofesionalTools.LOG("Y:" + req.responseText);
				//Y:{"ResultSet":{"totalResultsAvailable":"209","firstResultPosition":"1","totalResultsReturned":"0","content":"\n    "}}
				var r = /totalResultsAvailable['"]\s*:\s*['"]([^"']*)"/gi;
				var m = r.exec(req.responseText);
				if (null!=m) {
				    SeoprofesionalTools.LOG("RANK=" + m[1]);
				    rank = 1*m[1];
				    m = r.exec();
				    while (null!=m) {
					m = r.exec();
				    }
				}
				if (null==rank) {
					tab.setAttribute("x-seop-value-" + this.name, 0);
					SeoprofesionalTools.LOG("error fetching S-RANK for " + uri + "\n|" + req.responseText + "|");
				} else {
					tab.setAttribute("x-seop-value-" + this.name, rank);
					SeoprofesionalController.seopdb.add_rank(uri, this.id, rank);
				}
			}
			tab.setAttribute("x-seop-status-" + this.name, req.status);
			SeoprofesionalTools.LOG("setting status: " + this.name + "-status --> " + req.status + " for " + uri);
			if (gBrowser.selectedBrowser==tab) {
				SeoprofesionalController.tabSelected(null);
			}
		}
	},
	is_my_id: function(id) {
		var prefix = "seop-"+this.name;
		return prefix==id.substring(0, prefix.length);
	},
	_x_sentinel_: 0
},
urlBarListener: {
  QueryInterface: function(aIID) {
   if (aIID.equals(Ci.nsIWebProgressListener) ||
       aIID.equals(Ci.nsISupportsWeakReference) ||
       aIID.equals(Ci.nsISupports))
     return this;
   throw Components.results.NS_NOINTERFACE;
  },

  onLocationChange: function(aProgress, aRequest, aURI) {
    SeoprofesionalController.tabSelected(null);
  },

  onStateChange: function(aWebProgress, aRequest, aFlag, aStatus) {/*
   // If you use myListener for more than one tab/window, use
   // aWebProgress.DOMWindow to obtain the tab/window which triggers the state change
   if(aFlag & STATE_START)
   {
     // This fires when the load event is initiated
   }
   if(aFlag & STATE_STOP)
   {
     // This fires when the load finishes
   }*/
  },

  onProgressChange: function(a, b, c, d, e, f) {},
  onStatusChange: function(a, b, c, d) {},
  onSecurityChange: function(a, b, c) {}
},
/***
Changing the way how the internal state is handled. Now, whenever 
we have got any event, we just call tabSelected, which will take
care of the window. 
First of all, it checks, whether the active uri is the same as uri
set to the attribute "x-seop-uri". If it is not, it will initiate 
the ranks fetching. Otherwise, the rank fetching initialization 
is skipped.
After that the display of the ranks is refreshed.
***/
onLoad: function() {
	// Listen for webpage loads
	gBrowser.addProgressListener(SeoprofesionalController.urlBarListener, Ci.nsIWebProgress.NOTIFY_LOCATION);

	// we will need this in the sidebar
	gBrowser.openUILink = openUILink;

	gBrowser.tabContainer.addEventListener("TabSelect", SeoprofesionalController.tabSelected, false);
	//document.getElementById("appcontent").addEventListener("DOMContentLoaded", SeoprofesionalController.onPageLoaded, true);
	window.addEventListener("pageshow", SeoprofesionalController.onPageLoaded, true);

	this.strings = document.getElementById("seop-strings");
	this.sb_main = document.getElementById("seop-main");
	this.sb_write = document.getElementById("seop-write")

	this.disptype = 3;
	this.fetchers = [ SeoprofesionalController.srank_fetcher, SeoprofesionalController.pagerank_fetcher, SeoprofesionalController.ylinks_fetcher ];
	SeoprofesionalController.seop_global.fetchers = this.fetchers;
	SeoprofesionalController.seop_global.menulinks_default = [
			[true, escape("WHOIS"), "http://network-tools.com/default.asp?prog=whois&host=%d", true ],
			[true, escape(SeoprofesionalController.strings.getString("backlinks.yahoo")), "http://siteexplorer.search.yahoo.com/search?bwm=i&bwmf=u&bwms=p&fr=siteexplorer&fr2=seo-rd-se&p=%s", true ],
			[true, escape(SeoprofesionalController.strings.getString("site.count.seznam")), "http://search.seznam.cz/?q=site:%d&mod=f", true ],
			[true, escape(SeoprofesionalController.strings.getString("site.count.google")), "http://www.google.com/search?q=site:%d", true ],
			[true, escape("Google Analytics"), "https://www.google.com/analytics", true ],
			[true, escape("Google Keyword Tool"), "https://adwords.google.com/select/KeywordToolExternal", true ],
			[true, escape("Google Insights"), "http://www.google.com/insights/search/", true ],
			[true, escape(SeoprofesionalController.strings.getString("seznam.searchability")), "http://search.seznam.cz/stats?collocation=seo", true ]
		];

	this.prefs = Cc["@mozilla.org/preferences-service;1"]
		.getService(Ci.nsIPrefService)
		.getBranch("extensions.seoprofesional.");
	this.prefs.QueryInterface(Ci.nsIPrefBranch2);
	this.loadprefs();
	this.prefs.addObserver("", this, false);
	try {
		SeoprofesionalController.ylinks_fetcher.appid = this.prefs.getCharPref("ylinks.appid");
	} catch(e) {
		SeoprofesionalTools.LOG("No yahoo app id specified!");
		SeoprofesionalController.ylinks_fetcher.appid = "YahooDemo";
	}
	SeoprofesionalController.seop_global.date_format = this.strings.getString("dateformat");

	SeoprofesionalController.findFetchersCSS();

	SeoprofesionalController.globalToggle(true);
	this.initialized = true;
},
uris_to_top: function(uri) {
	var ret = [];
	// we expect schema://hostname.or.ip/partx/party/partz#safdo?akuhfd
	var tail = uri.search(/[#?&]/)
	if (-1==tail) {
		ret.push(uri);
	} else {
		ret.push(uri.substr(0, tail));
		ret.push(uri);
		uri = uri.substr(0, tail);
	}
	tail = uri.lastIndexOf('/');
	if (tail+1==uri.length) {
		uri = uri.substr(0, tail);
		tail = uri.lastIndexOf('/', tail);
	}
	while (tail>10) {
		ret.push(uri.substr(0, tail+1));
		tail = uri.lastIndexOf('/', tail-1);
	}
	return ret;
},
findFetchersCSS: function() {
	var r, i;
	var rules;
	for (r = 0;r<document.styleSheets.length;r++) {
		if ("chrome://seoprofesional/skin/overlay.css"!=document.styleSheets[r].href)	continue;
		rules = document.styleSheets[r].cssRules;
		for (i = 0;i<rules.length;i++) {
			if ("#seop-"==rules[i].selectorText.substr(0, 6)) {
				for (fi = 0; fi<this.fetchers.length;fi++) {
					var f = this.fetchers[fi];
					if ("#seop-"+f.name+"-f"==rules[i].selectorText) {
						f.color = rules[i].style.backgroundColor;
					}
				}
			}
		}
	}
},
onUnLoad: function() {
	gBrowser.removeProgressListener(SeoprofesionalController.urlBarListener);

	//document.getElementById("appcontent").removeEventListener("DOMContentLoaded", SeoprofesionalController.onPageLoaded, true);
	window.removeEventListener("pageshow", SeoprofesionalController.onPageLoaded, true)
	gBrowser.tabContainer.removeEventListener("TabSelect", SeoprofesionalController.tabSelected, false);

	this.prefs.removeObserver("", this);
},
loadprefs: function() {
	for (var i = 0;i<SeoprofesionalController.fetchers.length;i++) {
		var f = SeoprofesionalController.fetchers[i];
		f.enabled = 1;
		f.refresh = 0;
		try {
			f.enabled = this.prefs.getBoolPref(f.name);
			f.refresh = this.prefs.getIntPref(f.name + ".refresh");
		} catch (e) {
			SeoprofesionalTools.LOG("loadprefs: caught on " + f.name + ":" + e);
		}
	}
	try {
		this.disptype = this.prefs.getIntPref("disptype");
	} catch (e) {
	}
	SeoprofesionalController.loadMenuLinks();
},
loadMenuLinks: function() {
	try {
		SeoprofesionalController.menulinks = JSON.parse(SeoprofesionalController.prefs.getCharPref("menulinks"));
	} catch (e) {
		SeoprofesionalTools.LOG("Error loading menulinks: " + e);
		SeoprofesionalController.menulinks = SeoprofesionalController.seop_global.menulinks_default;
	}
	SeoprofesionalController.seop_global.menulinks = SeoprofesionalController.menulinks;
	SeoprofesionalController.rebuildMenuLinks();
},
observe: function(subject, topic, data) {
	SeoprofesionalTools.LOG("observe:" + subject + "," + topic + "," + data + "<");
	if ("nsPref:changed"!=topic) {
		return;
	}
	if ("disptype"==data) {
		this.disptype = this.prefs.getIntPref("disptype");
		this.fillContainer();
		return ;
	}
	if ("menulinks"==data) {
		SeoprofesionalTools.LOG("menulinks updated!!!");
		SeoprofesionalController.loadMenuLinks();
		return ;
	}
	for (var i = 0;i<SeoprofesionalController.fetchers.length;i++) {
		var f = SeoprofesionalController.fetchers[i];
		if (f.name==data) {
			f.enabled = this.prefs.getBoolPref(data);
			this.fillContainer();
			SeoprofesionalTools.LOG("FETCHER " + f.name + " dis/enABLED:" + f.enabled);
			return ;
		} else if (f.name + ".refresh"==data) {
			f.refresh = this.prefs.getIntPref(data);
			SeoprofesionalTools.LOG("FETCHER " + f.name + " refresh:" + f.refresh);
			return ;
		}
	}
},
globalToggle: function(s) {
	SeoprofesionalController.on = s;
	SeoprofesionalController.sb_main.src = s ? "chrome://seoprofesional/skin/e.png" : "chrome://seoprofesional/skin/d.png";
	//FIXME: When we turn on, should we start fetching rank for current page? Or even for all pages?
	// I think we should not because the user chose not to fetch those pages...
	SeoprofesionalController.fillContainer();
},
mainClick: function(event) {
	if (0==event.button) {
		this.globalToggle(!this.on);
	}
},
fillContainer: function() {
	var el = document.getElementById("seop-container");
	var x;
	SeoprofesionalTools.clear_subnodes(el);
	if (!SeoprofesionalController.on) {
		return ;
	}
	SeoprofesionalTools.LOG("SEOP.ON:" + SeoprofesionalController.on);
	x = document.createElement("label");
	x.setAttribute("height", "16px");
	x.setAttribute("width", "1px");	// FIXME: stupid!!!
	el.appendChild(x);
	for (var i = 0;i<SeoprofesionalController.fetchers.length;i++) {
		var f = SeoprofesionalController.fetchers[i];
		SeoprofesionalTools.LOG("f:" + f.name + "-" + f.enabled + ";f=" + f.flags);
		if (f.enabled) {
			x = document.createElement("label");
			x.setAttribute("id", "seop-" + f.name + "-h");
			x.setAttribute("tooltip", "seop-tip");
			x.setAttribute("onclick", "document.getElementById('seop-tip').openPopup(document.getElementById('seop-container'), 'before_start', -1, -1, false, false)");
			el.appendChild(x);
			if (f.flags & SeoprofesionalController.FETCHER_NOBARS || this.disptype & 1) {
				x = document.createElement("label");
				x.setAttribute("value", "");
				x.setAttribute("id", "seop-" + f.name);
				x.setAttribute("tooltip", "seop-tip");
				x.setAttribute("onclick", "document.getElementById('seop-tip').openPopup(document.getElementById('seop-container'), 'before_start', -1, -1, false, false)");
				el.appendChild(x);
			}
			if (f.flags & SeoprofesionalController.FETCHER_NOBARS) {
			} else if (this.disptype & 2) {
				x = document.createElement("hbox");
				x.setAttribute("id", "seop-" + f.name + "-f");
				x.setAttribute("class", "seop-full-bar")
				x.setAttribute("width", 0);
				x.setAttribute("tooltip", "seop-tip");
				x.setAttribute("onclick", "document.getElementById('seop-tip').openPopup(document.getElementById('seop-container'), 'before_start', -1, -1, false, false)");
				el.appendChild(x);
				x = document.createElement("hbox");
				x.setAttribute("id", "seop-" + f.name + "-e");
				x.setAttribute("class", "seop-empty-bar")
				x.setAttribute("width", SeoprofesionalController.SEOP_BAR_SIZE);
				x.setAttribute("tooltip", "seop-tip");
				x.setAttribute("onclick", "document.getElementById('seop-tip').openPopup(document.getElementById('seop-container'), 'before_start', -1, -1, false, false)");
				el.appendChild(x);
			}
		}
	}
	this.tabSelected();
},
setBars: function (f, val) {
	if (0!=val) {
		val = Math.floor(SeoprofesionalController.SEOP_BAR_SIZE*val/f.get_max(null));
	}
	SeoprofesionalTools.set_attr("seop-" + f.name + "-f", "width", val);
	SeoprofesionalTools.set_attr("seop-" + f.name + "-e", "width", SeoprofesionalController.SEOP_BAR_SIZE-val);
},
updateStatus: function (f, uri) {
	var st = gBrowser.selectedBrowser.getAttribute("x-seop-status-" + f.name);
	if (200==st) {
		var val = gBrowser.selectedBrowser.getAttribute("x-seop-value-" + f.name);
		if (f.flags & SeoprofesionalController.FETCHER_NOBARS || 1 & this.disptype) {
			SeoprofesionalTools.set_attr("seop-"+f.name, "value", val);
		}
		if (f.flags & SeoprofesionalController.FETCHER_NOBARS) {
		} else if (2 & this.disptype) {
			this.setBars(f, val);
		}
	} else {
		var v = SeoprofesionalController.seopdb.get_rank(uri, f.id);
		if (null==v) {
			v = [ 0, 0 ];
		}
		if (f.flags & SeoprofesionalController.FETCHER_NOBARS || 1 & this.disptype) {
			SeoprofesionalTools.set_attr("seop-"+f.name, "value", "(" + v[0] + ")");
		}
		if (f.flags & SeoprofesionalController.FETCHER_NOBARS) {
		} else if (2 & this.disptype) {
			this.setBars(f, v[0]);
		}
	}
},
initFetch: function(tab, uri) {
	if (!SeoprofesionalController.on) {
		SeoprofesionalTools.LOG("SEOP is OFF " + uri);
		return ;
	}
	uri = SeoprofesionalController.normalizeUri(uri);
	var now = new Date();
	tab.setAttribute("x-seop-uri", uri);
	for (var i = 0;i<SeoprofesionalController.fetchers.length;i++) {
		f = SeoprofesionalController.fetchers[i];
		tab.setAttribute("x-seop-status-" + f.name, 0);
		tab.setAttribute("x-seop-value-" + f.name, 0);
		if (f.enabled) {
			var refetch = 1;
			if (0==f.refresh) {
			} else if (""==SeoprofesionalController.seopdb.is_whitelisted(uri)) {
			} else {
				var v = SeoprofesionalController.seopdb.get_rank(uri, f.id);
				if (null!=v) {
					var d = v[1];
					d.setDate(d.getDate()+f.refresh);
					if (d>now) {
						refetch = 0;
						SeoprofesionalTools.LOG("SKIPPING FETCH:" + f.name + " refresh:" + f.refresh);
					}
				}
			}
			if (refetch)		SeoprofesionalController.fetchers[i].fetch(tab, uri);
		}
	}
},
tabSelected: function (event) {
	if (!SeoprofesionalController.on) {
		return ;
	}
	// !!! event CAN be null !!!
	var uri = ""+gBrowser.selectedBrowser.contentDocument.location;
	var stored_uri = gBrowser.selectedBrowser.getAttribute("x-seop-uri");

	uri = SeoprofesionalController.normalizeUri(uri);

	if (""!=SeoprofesionalController.seopdb.is_whitelisted(uri)) {
		SeoprofesionalController.sb_write.setAttribute("src", "chrome://seoprofesional/skin/we.png");
	} else {
		SeoprofesionalController.sb_write.setAttribute("src", "chrome://seoprofesional/skin/wd.png");
	}

	if (!SeoprofesionalController.isRankable(uri)) {
		SeoprofesionalTools.set_attr("seop-container", "hidden", true);
		return ;
	}

	if (uri!=stored_uri) {
		SeoprofesionalController.initFetch(gBrowser.selectedBrowser, uri);
	}

	SeoprofesionalTools.set_attr("seop-container", "hidden", false);
	for (var i = 0;i<SeoprofesionalController.fetchers.length;i++) {
		if (SeoprofesionalController.fetchers[i].enabled) {
			SeoprofesionalController.updateStatus(SeoprofesionalController.fetchers[i], uri);
		}
	}
},
unhighlight: function(fs) {
	if (null==fs) {
		var docShell = gBrowser.contentWindow.QueryInterface(Ci.nsIInterfaceRequestor)
					.getInterface(Ci.nsIWebNavigation)
					.QueryInterface(Ci.nsIDocShell);

		var controller = docShell.QueryInterface(Ci.nsIInterfaceRequestor)
					   .getInterface(Ci.nsISelectionDisplay)
					   .QueryInterface(Ci.nsISelectionController);
		fs = controller.getSelection(Ci.nsISelectionController.SELECTION_FIND);
	}
	fs.removeAllRanges();
},
onLinks: function() {
	var windowManager = Cc['@mozilla.org/appshell/window-mediator;1'].getService();
	var windowManagerInterface = windowManager.QueryInterface(Ci.nsIWindowMediator);
	var windows = windowManagerInterface.getEnumerator("Browser:page-info");

	var uri = ""+gBrowser.selectedBrowser.contentDocument.location;

	// Check for windows matching the url
	while (windows.hasMoreElements()) {
		var currentWindow = windows.getNext();
		if (uri==currentWindow.document.documentElement.getAttribute("relatedUrl")) {
			currentWindow.focus();
			return;
		}
	}
	
	window.openDialog("chrome://browser/content/pageinfo/pageInfo.xul",
			"_blank",
			"chrome,toolbar,dialog=no,resizable",
			{initialTab: "seopTab"});
},
rebuildMenuLinks: function() {
	var menu = document.getElementById("seop-menu");
	// first, remove the old "menulinks"
	var to_remove = [];
	var el = menu.firstChild;
	while(el) {
		if (1==el.nodeType) {
			if (0==el.id.indexOf("seop-ml-")) {
				to_remove.push(el);
			}
		}
		el = el.nextSibling;
	}
	for (var i = 0;i<to_remove.length;i++) {
		el = to_remove[i];
		el.parentNode.removeChild(el);
	}
	for (var i = 0;i<SeoprofesionalController.menulinks.length;i++) {
		if (SeoprofesionalController.menulinks[i][0]) {
			var ne = document.createElement("menuitem");
			ne.setAttribute("id", "seop-ml-" + i);
			ne.setAttribute("label", unescape(SeoprofesionalController.menulinks[i][1]));
			ne.setAttribute("oncommand", "SeoprofesionalController.onMenuLink('" + SeoprofesionalController.menulinks[i][2] + "')");
			menu.appendChild(ne);
		}
	}
},
onMenuLink: function (uri) {
	var current = ""+gBrowser.selectedBrowser.contentDocument.location;
	if (-1!=uri.indexOf("%s")) {
		uri = uri.replace("%s", escape(current));
	} else if (-1!=uri.indexOf("%d")) {
		uri = uri.replace("%d", escape(SeoprofesionalTools.get_domain(current)));
	}
	SeoprofesionalTools.LOG(uri);
	gBrowser.addTab(uri);
},
onMenuShowing: function (event) {
	if ("seop-menu"!=event.target.id) {
		return true;
	}
	var uri = ""+gBrowser.selectedBrowser.contentDocument.location;
	if (!SeoprofesionalController.isRankable(uri)) {
		SeoprofesionalTools.set_attr("seop-menu-enable", "hidden", true);
		SeoprofesionalTools.set_attr("seop-menu-disable", "hidden", true);
	} else {
		var wl = SeoprofesionalController.seopdb.is_whitelisted(uri);
		if (""==wl) {
			SeoprofesionalTools.set_attr("seop-menu-enable", "hidden", false);
			SeoprofesionalTools.set_attr("seop-menu-disable", "hidden", true);
			var menu = document.getElementById("seop-sub-enable");
			SeoprofesionalTools.clear_subnodes(menu);
			var uris = this.uris_to_top(uri);
			for (var i = 0;i<uris.length;i++) {
				SeoprofesionalTools.addmenu(menu, uris[i], "SeoprofesionalController.enableUri('"+uris[i]+"')");
			}
		} else {
			SeoprofesionalTools.set_attr("seop-menu-enable", "hidden", true);
			SeoprofesionalTools.set_attr("seop-menu-disable", "hidden", false);
			var menu = document.getElementById("seop-sub-disable");
			SeoprofesionalTools.clear_subnodes(menu);
			SeoprofesionalTools.addmenu(menu, wl, "SeoprofesionalController.disableUri('"+wl+"')");
		}
	}
},
enableUri: function(uri) {
	SeoprofesionalController.seopdb.whitelist(uri);
	SeoprofesionalController.cond_refetch(uri);
	this.tabSelected(null);
},
disableUri: function(uri) {
	SeoprofesionalController.seopdb.un_whitelist(uri);
	this.tabSelected(null);
},
cond_refetch: function(base_uri) {
	// this can be used either to re-fetch ranks for all tabs
	// or to re-fetch ranks for tabs whose uri matches to supplied
	// base_uri. Used when the storing has been enabled.

	var wm = Cc["@mozilla.org/appshell/window-mediator;1"].getService(Ci.nsIWindowMediator);
	var browserEnumerator = wm.getEnumerator("navigator:browser");
	while (browserEnumerator.hasMoreElements()) {
		var browserWin = browserEnumerator.getNext();
		var tabbrowser = browserWin.getBrowser();
		var numTabs = tabbrowser.browsers.length;
		for(var index=0; index<numTabs; index++) {
			var currentBrowser = tabbrowser.getBrowserAtIndex(index);
			var uri = ""+currentBrowser.contentDocument.location;
			if (SeoprofesionalController.isRankable(uri)) {
				if (null==base_uri || base_uri==uri.substr(0, base_uri.length)) {
					SeoprofesionalTools.LOG("RE-FETCHING: " + uri + " for " + base_uri);
					SeoprofesionalController.initFetch(currentBrowser, uri);
				}
			}
		}
	}
},
onPageLoaded: function (event) {
	var doc = event.originalTarget;
	var uri = ""+doc.location;

	var wm = Cc["@mozilla.org/appshell/window-mediator;1"].getService(Ci.nsIWindowMediator);
	var browserEnumerator = wm.getEnumerator("navigator:browser");
	var found = 0;
	//FIXME: this is rather a stupid way to get associated browser for the loaded document. 
	// Is there a better way?!?
	while (!found && browserEnumerator.hasMoreElements()) {
		var browserWin = browserEnumerator.getNext();
		var tabbrowser = browserWin.getBrowser();
		// Check each tab of this browser instance
		var numTabs = tabbrowser.browsers.length;
		for(var index=0; index<numTabs; index++) {
			var currentBrowser = tabbrowser.getBrowserAtIndex(index);
			if (currentBrowser.contentDocument==doc) {
				found = currentBrowser;
				break;
			}
		}
	}
	if (found) {
		if (gBrowser.selectedBrowser==found) {
			SeoprofesionalController.tabSelected(null);
		} else if (SeoprofesionalController.isRankable(uri)) {
			var stored_uri = found.getAttribute("x-seop-uri");
			if (stored_uri!=uri) {
				SeoprofesionalController.initFetch(found, uri);
			}
		}
	} else {
		// log this again when you get rid of frames, iframes and such
		//SeoprofesionalTools.LOG("overlay.js#1:THIS SHOULD NOT HAPPEN  !!!" + uri);
	}
},
isRankable: function(uri) {
	return "http://"==uri.substring(0, 7) || "https://"==uri.substring(0, 8);
},
normalizeUri: function(uri) {
	/**
	 * Returns an url seop remembers. Currently just removes everything
	 * after #
	 */
	var hash = uri.indexOf("#");
	if (-1!=hash)
		uri = uri.substring(0, hash);
	SeoprofesionalTools.LOG("Normalized: " + uri);
	return uri;
},
counter: 0,
tipShowing: function(event) {
	var uri = ""+gBrowser.selectedBrowser.contentDocument.location;
	if (!SeoprofesionalController.seopdb.is_whitelisted(uri)) {
		return false;
	}
	return true;
},
tipShown: function(event) {
	var uri = ""+gBrowser.selectedBrowser.contentDocument.location;
	if (!SeoprofesionalController.seopdb.is_whitelisted(uri)) {
		return false;
	}
	SeoprofesionalTools.set_attr("seop-tip-footer", "value", uri);
	SeoprofesionalTools.set_attr("seop-tip-frame", "src", "chrome://seoprofesional/content/plot.html?" + this.counter++ + "uri=" + uri);
	return true;
},
_x_sentinel_: 0
};

Components.utils.import("resource://seoprofesional/seopdb.jsm", 	SeoprofesionalController);

window.addEventListener("load", function(e) { SeoprofesionalController.onLoad(e); }, false);
window.addEventListener("unload", function(e) { SeoprofesionalController.onUnLoad(e); }, false);

/*
var vars=[]; for(var v in this){vars.push(v);} vars.sort();
SeoprofesionalTools.LOG("VARS=================================");
SeoprofesionalTools.LOG("VARS:" + vars);
SeoprofesionalTools.LOG("THIS:" + this);
SeoprofesionalTools.LOG("VARS=================================");
*/

